package com.jady.main;

import java.io.IOException;
import java.util.Map;

import com.sun.jdi.Bootstrap;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.VirtualMachineManager;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import com.sun.tools.jdi.SocketAttachingConnector;

public class VMAcquirer {

	/**
	 * Call this with the localhost port to connect to.
	 */
	public VirtualMachine connect(int port) throws IOException {
		String strPort = Integer.toString(port);
		AttachingConnector connector = getConnector();
		try {
			// for local hooking to TestJad.. dont know what it is called,
			//but the debugee is waiting this connector to attach to start its execution
			VirtualMachine vm = connect(connector, strPort);
			
			//VirtualMachine vm = remoteVMHook("localhost", port);
			return vm;
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	@SuppressWarnings("unchecked")
	public VirtualMachine remoteVMHook(String machine, int port) throws InterruptedException {
		SocketAttachingConnector connector = getConnectorRemote();
		Map connectorArguments = connector.defaultArguments();
		Connector.Argument host = (Connector.Argument) connectorArguments.get("hostname");
		Connector.Argument portArg = (Connector.Argument) connectorArguments.get("port");

		host.setValue(machine);

		portArg.setValue(String.valueOf(port));
		VirtualMachine vm = null;
		try {
			vm = connector.attach(connectorArguments);
		} catch (IOException exc) {
			throw new Error("Unable to hook to target JVM: [" + machine + ":" + port + "] due to " + exc);
		} catch (IllegalConnectorArgumentsException exc) {
			throw new Error("Unable to hook due to error: " + exc);
		}
		return vm;

	}
	
	private AttachingConnector getConnector() {
		VirtualMachineManager vmManager = Bootstrap.virtualMachineManager();
		for (Connector connector : vmManager.attachingConnectors()) {
			System.out.println(connector.name());
			if ("com.sun.jdi.SocketAttach".equals(connector.name())) {
				return (AttachingConnector) connector;
			}
		}
		throw new IllegalStateException();
	}
	private SocketAttachingConnector getConnectorRemote() {
		VirtualMachineManager vmManager = Bootstrap.virtualMachineManager();
		for (Connector connector : vmManager.attachingConnectors()) {
			System.out.println(connector.name());
			if ("com.sun.jdi.SocketAttach".equals(connector.name())) {
				return (SocketAttachingConnector) connector;
			}
		}
		throw new IllegalStateException();
	}

	private VirtualMachine connect(AttachingConnector connector, String port)
			throws IllegalConnectorArgumentsException, IOException {
		Map<String, Connector.Argument> args = connector.defaultArguments();
		Connector.Argument pidArgument = args.get("port");
		if (pidArgument == null) {
			throw new IllegalStateException();
		}
		pidArgument.setValue(port);

		return connector.attach(args);
	}

}
